#include "yaco.h"

struct uti {
  std::string a = "";
  int i = 0;
};

/// Type converter
namespace cxxopts {
namespace values {

template <>
ErrOr<void>
parse_value<uti>(const std::string& text, uti& value) {
  value.a = text;
  value.i = (int) text.length();
  return true;
}

}
}

yaco::Opt<bool> debug("d",
                      yaco::cat("Analysis"),
                      yaco::init(false),
                      yaco::desc("Enable debug"),
                      yaco::callback([](const bool &yes){
                                       std::cout << "Option debug set as " << yes << std::endl;
                      })
                      );
yaco::Opt<bool> coverage("c,cover",
                         yaco::cat("Analysis")
                         );
yaco::Opt<bool> help("h,help",
                     yaco::desc("display help messages.\n"
                                "=== Here is more detail ==="),
                     yaco::cat("Auxiliary")
                     );
yaco::Opt<int> job("j,job",
                   yaco::desc("jobs"),
                   yaco::value_desc("N")
                   );
yaco::Opt<struct uti> utisw("u"
                            );
yaco::Opt<std::string> output("o",
                              yaco::init("a.out"),
                              yaco::value_desc("filename")
                              );
// These are two position-related parameters.
yaco::Opt<std::string> head(yaco::value_desc("head file"), yaco::Positional);
yaco::Opt<std::vector<std::string>> inputs("inputs",
                                           yaco::value_desc("input files"),
                                           yaco::Positional
                                           );
enum OptLevel { Debug, O1, O2, O3 };
yaco::Opt<OptLevel> OptimizationLevel(
    "opt",
    yaco::desc("Choose optimization level."),
    yaco::values(
        coEnumValN(Debug, "g", "No optimizations, enable debugging"),
        coEnumVal(O1, "Trivial optimizations"),
        coEnumVal(O2, "Default optimizations"),
        coEnumVal(O3, "Expensive optimizations")
        )
    );
yaco::Opt<std::vector<std::string>> used("use",
                                         yaco::desc("multiple used")
                                         );

int main(int argc, char **argv)
{
  yaco::enparse(argc, argv);

  if (job.IsSpecified())
  {
    int n = job;
    std::cout << "Parallel jobs: " << n << std::endl;
  }

  if (debug)
  {
    std::cout << "debug on" << std::endl;
  }
  else
  {
    std::cout << "debug off" << std::endl;
  }

  std::cout << "optimization level: ";
  switch (OptimizationLevel) {
  case OptLevel::Debug: std::cout << "debug" << std::endl; break;
  case OptLevel::O1:    std::cout << "O1"    << std::endl; break;
  case OptLevel::O2:    std::cout << "O2"    << std::endl; break;
  case OptLevel::O3:    std::cout << "O3"    << std::endl; break;
  }

  if (coverage)
  {
    std::cout << "coverage on" << std::endl;
  }
  else
  {
    std::cout << "coverage off" << std::endl;
  }

  if (utisw.IsSpecified())
  {
    std::cout << "util args: " << utisw.a
              << " len=" << utisw.i
              << std::endl;
  }

  if (head.IsSpecified())
  {
    std::cout << "head: " << head << std::endl;
  }
  if (inputs.IsSpecified())
  {
    std::cout << "inputs: ";
    for (auto &input : inputs)
    {
      std::cout << input << " ";
    }
    std::cout << std::endl;
  }

  if (used.IsSpecified())
  {
    std::cout << "used: ";
    for (auto &u : used)
    {
      std::cout << u << " ";
    }
    std::cout << std::endl;
  }

  if (help.IsSpecified() || argc == 1)
  {
    std::cout << yaco::help() << std::endl;
    exit(0);
  }

  return 0;
}